package rbb.itm5.bwinf.roboter.Control;

import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;
import rbb.itm5.bwinf.roboter.Model.Obstacle;


import rbb.itm5.bwinf.roboter.Model.Room;

/**
 * Diese Klasse händelt alle Events aus der View und dem Model.
 *
 * @author Dominik Jakielski
 */
public class ControlerEvents extends KeyAdapter {

    private Controler crt;
    private Obstacle ob = null;

    /**
     * @param crt Haupt-Controler für den Zugriff auf Model und View
     *
     */
    public ControlerEvents(Controler crt) {
        this.crt = crt;
    }

    /**
     * Diese Methode wird von der View aufgerufen, wenn diese neu gezeichnet
     * werden soll. Sie startet die einzelnen Zeichnungsprozesse der View und
     * übergibt ihr die Daten des Model.
     *
     */
    public void repaintRoomFromView() {
        //System.out.println("RePaint at "+crt.getRoboter().getPostion().x+" - "+crt.getRoboter().getPostion().y);
        if (crt.getRoom().getSize().width <= 0 || crt.getRoom().getSize().height <= 0) {
            return;
        }
        crt.getView().getRoom().setRoomModel(crt.getRoom());
        crt.getView().getRoom().paintRaster();
        crt.getView().getRoom().paintBorder();
        crt.getView().getRoom().paintObstacles();
        if (crt.getDriver() != null && crt.getDriver().obstacles != null && !crt.getDriver().obstacles.isEmpty() && crt.getDriver().isPaintObstacles()) {
            crt.getView().getRoom().paintObstacles(crt.getDriver().obstacles, Color.orange, crt.getRoom().getRoboterStartX(), crt.getRoom().getRoboterStartY());
        }
        if (crt.getDriver().isPaintGoneSteps()) {
            crt.getView().getRoom().paintGoneSteps(crt.getRoboter());
        }
        crt.getView().getRoom().paintRoboter(crt.getRoboter());
    }

    /**
     * Zeichnet die View neu. Nach dem Aufruf wird die Methode
     * repaintRoomFromView() gestartet um den Zeichnungsvorgang zu starten.
     *
     *
     */
    public void repaintView() {
        crt.getView().getRoom().repaint();
        crt.getView().getControlPanel().setSteps(crt.getRoboter().getStepCount());
        if(crt.getDriver().isStoped()) crt.getView().getControlPanel().setRunTime(0); else crt.getView().getControlPanel().setRunTime(crt.getDriver().getRuntime());
    }

    /**
     * Händelt alle Tastertur-Eingaben.
     *
     * @param e KeyEvent
     */
    @Override
    public void keyPressed(KeyEvent e) {
        try {
            e.consume();
            if (crt.getRoboter().checkGoalHasFound() && e.getKeyCode() != KeyEvent.VK_S) {
                crt.getDriver().stop(true);
                return;
            }
            switch (e.getKeyCode()) {
                case KeyEvent.VK_LEFT:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoboter().turnLeft();
                    break;
                case KeyEvent.VK_RIGHT:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoboter().turnRight();
                    break;
                case KeyEvent.VK_UP:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    if (e.isShiftDown()) {
                        crt.getRoboter().moveForward();
                    } else {
                        crt.getRoboter().goForward();
                    }
                    System.out.println("Look=" + Roboter.DIRECTION[crt.getRoboter().getDirection()] + "=" + crt.getRoboter().hasColision() + " - "
                            + Roboter.DIRECTION[crt.getRoboter().getDirectionLeft()] + "=" + crt.getRoboter().hasLeftColision() + " - "
                            + Roboter.DIRECTION[crt.getRoboter().getDirectionRight()] + "=" + crt.getRoboter().hasRightColision());
                    break;
                case KeyEvent.VK_BACK_SPACE:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoboter().goBack();
                    break;
                case KeyEvent.VK_D:
                    startDriver();
                    break;
                case KeyEvent.VK_S:
                    stopDriver();
                    break;
                case KeyEvent.VK_P:
                    pauseDriver();
                case KeyEvent.VK_SPACE:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoom().saveRoom("maps/Test.txt");
                    loadRoomBox();
                    break;
                case KeyEvent.VK_PLUS:
                case 107:
                    increaseRoomGridSize();
                    break;
                case KeyEvent.VK_MINUS:
                case 109:
                    decreaseRoomGridSize();
                    break;
                case KeyEvent.VK_N:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    reloadRoom("maps/raum1.txt");
                    break;
                case KeyEvent.VK_1:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    ob = new Obstacle(1, 1, 1, 1);
                    ob.setEditable(true);
                    crt.getRoom().getObstacles().add(ob);
                    break;
                case KeyEvent.VK_2:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    if (e.isShiftDown()) {
                        ob.setX(ob.getPostion().x - 1);
                    } else {
                        ob.setX(ob.getPostion().x + 1);
                    }
                    break;
                case KeyEvent.VK_3:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    if (e.isShiftDown()) {
                        ob.setY(ob.getPostion().y - 1);
                    } else {
                        ob.setY(ob.getPostion().y + 1);
                    }
                    break;
                case KeyEvent.VK_4:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    if (e.isShiftDown()) {
                        ob.setWidth(ob.getSize().width - 1);
                    } else {
                        ob.setWidth(ob.getSize().width + 1);
                    }
                    break;
                case KeyEvent.VK_5:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    if (e.isShiftDown()) {
                        ob.setHeight(ob.getSize().height - 1);
                    } else {
                        ob.setHeight(ob.getSize().height + 1);
                    }
                    break;

                case KeyEvent.VK_6:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoom().setEditable(true);
                    if (e.isShiftDown()) {
                        crt.getRoom().setRoboterStartX(crt.getRoom().getRoboterStartX() - 1);
                    } else {
                        crt.getRoom().setRoboterStartX(crt.getRoom().getRoboterStartX() + 1);
                    }
                    break;
                case KeyEvent.VK_7:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoom().setEditable(true);
                    if (e.isShiftDown()) {
                        crt.getRoom().setRoboterStartY(crt.getRoom().getRoboterStartY() - 1);
                    } else {
                        crt.getRoom().setRoboterStartY(crt.getRoom().getRoboterStartY() + 1);
                    }
                    break;


                case KeyEvent.VK_8:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoom().setEditable(true);
                    if (e.isShiftDown()) {
                        crt.getRoom().setWidth(crt.getRoom().getSize().width - 1);
                    } else {
                        crt.getRoom().setWidth(crt.getRoom().getSize().width + 1);
                    }
                    break;
                case KeyEvent.VK_9:
                    if (!getDriver().isStoped()) {
                        break;
                    }
                    crt.getRoom().setEditable(true);
                    if (e.isShiftDown()) {
                        crt.getRoom().setHeight(crt.getRoom().getSize().height - 1);
                    } else {
                        crt.getRoom().setHeight(crt.getRoom().getSize().height + 1);
                    }
                    break;


            }
            if (e.getKeyCode() >= KeyEvent.VK_0 && e.getKeyCode() <= KeyEvent.VK_9) {
                crt.getView().repaint();
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(ControlerEvents.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Läd einen neuen Raum und stellt alle Werte auf die Anfangswerte zurück.
     * Anschließend wird die View neu gezeichnet.
     *
     * @param roomFile Die Raumdatei in der der Raum beschrieben wird.
     *
     */
    public void reloadRoom(String roomFile) {
        if (!roomFile.startsWith("maps")) {
            roomFile = "maps/" + roomFile;
        }
        System.out.println("Lade: "+roomFile);
        crt.getDriver().obstacles.clear();
        crt.getRoboter().reset();
        if (crt.getRoom().loadRoom(roomFile)) {
            //crt.getView().initGui(crt.getRoom().getSize().width, crt.getRoom().getSize().height);
            //crt.getView().getRoom().setViewSize(crt.getRoom().getSize().width*rbb.itm5.bwinf.roboter.Model.Room.GridSize, crt.getRoom().getSize().height*rbb.itm5.bwinf.roboter.Model.Room.GridSize);
            crt.getView().getControlPanel().refreshModel();
            repaintView();
        }
    }

    /**
     * Gibt das aktuelle Fahrer-Programm zurück
     */
    public DriverInterface getDriver() {
        return crt.getDriver();
    }

    /**
     * Dieses Event wird aufgerufen, wenn die View initalisiert wurde und zum
     * ersten mal gezeichnet wird.
     */
    public void ViewWasFirstCalled() {
        repaintView();
        crt.getView().getControlPanel().refreshModel();
    }

    /**
     * Setzt die Wartezeit, für einen Schritt.
     */
    public void refreshWaitTime(int waitTime) {
        crt.getDriver().setWaitTime(waitTime);
    }

    /**
     * Dieses Event wird aufgerufen, wenn sich die Position des Roboters
     * geändert hat.
     *
     * @throws InterruptedException Die Exeption wird aufgerufen wenn das
     * Steuerungsprogramm(Driver) angehalten bzw. Pausiert werden soll.
     *
     */
    void roboterPositionChanged() throws InterruptedException {
        //getDriver().waitForNextStep();
    }

    public void setViewSize(int width, int height) {
        crt.getView().getRoom().setViewSize(width, height);
    }

    void refreshModel() {
        crt.getView().getControlPanel().refreshModel();
    }

    void loadRoomBox() {
        File maps = new File("maps");
        if (maps.isDirectory()) {
            String[] mapFiles = maps.list(new FilenameFilter() {
                @Override
                public boolean accept(File arg0, String arg1) {
                    return arg0.canRead() && arg1.toLowerCase().endsWith(".txt");
                }
            });
            if (mapFiles.length > 0) {
                crt.getView().getControlPanel().setRoomBoxModel(new DefaultComboBoxModel(mapFiles));
            }
        }
    }

    public void setDriver(Object Driver) {
        if (Driver instanceof String) {
            crt.setDriver(crt.getDriver((String) Driver));
        } else if (Driver instanceof DriverInterface) {
            crt.setDriver((DriverInterface) Driver);
        }
        crt.getView().getControlPanel().refreshModel();
    }

    public void startDriver() {
        getDriver().start();
    }

    public void pauseDriver() {
        getDriver().pause();
    }

    public void stopDriver() {
        if (getDriver().isStoped()) {
            getDriver().obstacles.clear();
            crt.getRoboter().reset();
            repaintView();
        } else {
            getDriver().stop();
        }
    }

    void driverStateChanged(int newState) {
        if (newState == DriverInterface.StateRunning) {
            crt.getView().getControlPanel().setDriverChangeState(false);
            crt.getView().getControlPanel().setLoadRoomState(false);
        } else {
            crt.getView().getControlPanel().setDriverChangeState(true);
            crt.getView().getControlPanel().setLoadRoomState(true);
        }
        
        if(newState == DriverInterface.StateReady){
            JOptionPane.showMessageDialog(crt.getView().getJFrame(), "Der Roboter hat sein Ziel gefunden.\n\nEr benötigte dafür "+crt.getRoboter().getStepCount()+" Schritte.", 
                    "Herzlichen Glückwunsch", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    public void increaseRoomGridSize() {
        if (Room.GridSize < 80) {
            Room.GridSize++;
        }
        crt.getView().getRoom().setViewSize(crt.getRoom().getSize().width * Room.GridSize, crt.getRoom().getSize().height * Room.GridSize);
        crt.getView().repaint();
    }

    public void decreaseRoomGridSize() {
        if (Room.GridSize > 1) {
            Room.GridSize--;
        }
        crt.getView().getRoom().setViewSize(crt.getRoom().getSize().width * Room.GridSize, crt.getRoom().getSize().height * Room.GridSize);
        crt.getView().repaint();
    }
}
